package log

import (
	"fmt"
	"os"
	"strings"
	"time"
)

type LogLine struct {
	LogContent *string
	LogTime    *time.Time
}

func (l *LogLine) string() *string {
	str := fmt.Sprintf("[%s] %s", l.LogTime.Format("2006-01-02 15:04:05"), *l.LogContent)
	return &str
}

type LogConfig struct {
	LogChanCap       int
	LogFileName      string
	LogWriteInterval int
}

type LogInstance struct {
	*LogConfig
	logChan      chan LogLine
	timer        *time.Ticker
	logCloseChan chan struct{}
	logWriteChan chan struct{}
}

func NewLogInstance() *LogInstance {
	if pkgVarLogConfig != nil {
		return &LogInstance{
			LogConfig: pkgVarLogConfig,
			logChan:   make(chan LogLine, pkgVarLogConfig.LogChanCap),
		}
	} else {
		return &LogInstance{
			LogConfig: DefaultLogConfig,
			logChan:   make(chan LogLine, DefaultLogConfig.LogChanCap),
		}
	}
}

func (l *LogInstance) writeLogFile() {
	logFileName := l.LogFileName + ".log"
	logFile, err := os.OpenFile(logFileName, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
	if err != nil {
		fmt.Println("open file error: ", err)
		return
	}
	defer logFile.Close()

	logLines, logChanLen := l.getLogLines()
	if logChanLen > 0 {
		logFile.WriteString(*logLines)
	}
}

func (l *LogInstance) getLogLines() (*string, int) {
	logChan := l.logChan
	logChanLen := len(logChan)
	logLinesStrBd := &strings.Builder{}
	for i := 0; i < logChanLen; i++ {
		logItem := <-logChan
		logLinesStrBd.WriteString(*logItem.string())
		logLinesStrBd.WriteString("\n")
	}
	logLines := logLinesStrBd.String()
	return &logLines, logChanLen
}

func (l *LogInstance) logMain() {
	// TODO: add1: 日志分割
	// TODO: add2: 日志清理

	// bug1: LogChan满的时候会阻塞主线程 ==> 容量阈值写
	// bug2: 主线程执行完成后直接退出，LogChan里面的数据没有写入文件 ==> CloseLog

	os.Remove(l.LogFileName + ".log")
	l.timer = time.NewTicker(time.Duration(l.LogWriteInterval) * time.Second)
	l.logCloseChan = make(chan struct{}, 1)
	l.logWriteChan = make(chan struct{}, 1)
	go func() {
		thresholdChan := make(chan struct{}, 1)
		defer close(thresholdChan)
		for {
			select {
			case <-l.timer.C: // 定时写
				// fmt.Println("log定时写")
				l.writeLogFile()
			case <-thresholdChan: // 容量阈值写
				// fmt.Println("log容量阈值写")
				l.writeLogFile()
			case <-l.logCloseChan:
				// fmt.Println("log关闭写")
				l.writeLogFile()
				l.logWriteChan <- struct{}{}
				return
			default:
				// 轮询
				logChanLen := len(l.logChan)
				if logChanLen >= l.LogChanCap*7/10 {
					thresholdChan <- struct{}{}
				} else {
					time.Sleep(time.Duration(l.LogWriteInterval) * time.Millisecond)
				}
			}
		}
	}()
}

func (l *LogInstance) logClose() {
	l.logCloseChan <- struct{}{}
	<-l.logWriteChan
	l.timer.Stop()
	close(l.logChan)
	close(l.logCloseChan)
	close(l.logWriteChan)
}
